package com.after.saas.log.aspect;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.after.saas.common.annotation.Log;
import com.after.saas.common.constants.CommonCodeEnum;
import com.after.saas.common.constants.Result;
import com.after.saas.common.model.dto.OperatorLogDTO;
import com.after.saas.common.model.vo.UserVO;
import com.after.saas.common.utils.AppUtil;
import com.after.saas.common.utils.ResponseUtil;
import com.after.saas.log.event.OperateLogEvent;
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Objects;


/**
 * @Classname LogAspcet
 * @Description TODO
 * @Date 2021/6/7 17:47
 * @Created by hjchen
 */


@Aspect
@Component
public class LogAspect {

    /**
     * 事件发布
     **/
    @Autowired
    private ApplicationContext applicationContext;

    private final Logger log = LoggerFactory.getLogger(LogAspect.class);

    /**
     * 配置通知
     *
     * @param joinPoint join point for advice
     */
    @AfterReturning(pointcut = "@annotation(logAnnotation)", returning = "retVal")
    public void logAfterReturning(JoinPoint joinPoint, Log logAnnotation, Object retVal) {
        Result result;
        if (retVal instanceof Result) {
            result = (Result) retVal;
        } else {
            result = ResponseUtil.FAILURE(retVal.toString());
        }
        buildException(joinPoint, logAnnotation, result);
    }

    /**
     * 配置通知
     *
     * @param joinPoint join point for advice
     */
    @AfterThrowing(pointcut = "@annotation(logAnnotation)", throwing = "e")
    public void logAfterThrowing(JoinPoint joinPoint, Log logAnnotation, Throwable e) {
        buildException(joinPoint, logAnnotation, ResponseUtil.FAILURE(e.getMessage()));
    }

    private OperatorLogDTO buildException(JoinPoint joinPoint, Log logAnnotation, Result result) {
        String userid = null;
        String content = result.getMsg();
        int code = result.getCode();
        String msg = result.getMsg();
        log.error("desc {},result {}", logAnnotation.value(), result.getData());
        OperatorLogDTO logDTO = new OperatorLogDTO();
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        Object data = result.getData();
        if (ObjectUtil.isNotEmpty(data)) {
            if (data instanceof UserVO) {
                userid = ((UserVO) data).getId();
            }
        }
        logDTO.setCreateBy(userid);
        if (code == CommonCodeEnum.SUCCESS.value()) {
            content = msg;
        } else {
            Object[] args = joinPoint.getArgs();
            if (ObjectUtil.isNotEmpty(args)) {
                content = JSON.toJSONString(joinPoint.getArgs());
            }
        }
        //目标方法名
        String name = StrUtil.isEmpty(logAnnotation.value()) ? method.getName() : logAnnotation.value();
        logDTO.setMethod(name);
        logDTO.setContent(content);
        logDTO.setCode(result.getCode());
        //获取浏览器
        String browser = AppUtil.getBrowser();
        logDTO.setOperUrl(Objects.requireNonNull(AppUtil.getRequest()).getRequestURI());
        //获取ip
        logDTO.setIp(AppUtil.getRemoteIP());
        logDTO.setIpAddr(browser);
        // 发布事件
        applicationContext.publishEvent(new OperateLogEvent(logDTO));
        return logDTO;
    }

}